package com.atguigu.gulimail.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.service.product.ProviderProductService;
import com.atguigu.common.utils.R;
import com.atguigu.gulimail.interceptor.CartInterceptor;
import com.atguigu.gulimail.service.CartService;
import com.atguigu.gulimail.vo.Cart;
import com.atguigu.gulimail.vo.CartItem;
import com.atguigu.gulimail.vo.SkuInfoEntity;
import com.atguigu.gulimail.vo.userInfoTo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author fangy
 * @date 2022-10-12 19:24
 */
@Service
@Slf4j
public class CartServiceImpl implements CartService {

    @Autowired
    StringRedisTemplate redisTemplate;


    @DubboReference(check = false)
    ProviderProductService providerProductService;

    @Autowired
    ThreadPoolExecutor executor;


    private final String CART_PREFIX = "gulimail:cart:";

    @Override
    public CartItem addToCart(Long skuId, Integer num) {

        BoundHashOperations<String, Object, Object> cartOps = getCartOps();

        String key = (String) cartOps.get(skuId.toString());

        if(StringUtils.isEmpty(key)){

            CartItem cartItem = new CartItem();

            CompletableFuture<Void> async = CompletableFuture.runAsync(() -> {

                R r = providerProductService.getSkuEntityById(skuId);

                SkuInfoEntity data = r.getData(new TypeReference<SkuInfoEntity>() {
                });

                cartItem.setSkuId(data.getSkuId());
                cartItem.setTitle(data.getSkuTitle());
                cartItem.setCheck(true);
                cartItem.setPrice(data.getPrice());
                cartItem.setCount(num);
                cartItem.setImage(data.getSkuDefaultImg());

            }, executor);

            CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {

                R skuAttrBySkuId = providerProductService.getSkuAttrBySkuId(skuId);

                List<String> data = skuAttrBySkuId.getData(new TypeReference<List<String>>() {
                });

                cartItem.setSkuAttr(data);

            }, executor);

            try {

                CompletableFuture.allOf(runAsync,async).get();

            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }

            String s = JSON.toJSONString(cartItem);
            cartOps.put(skuId.toString(),s);

            return cartItem;
        }
        else{

            CartItem item = JSON.parseObject(key, CartItem.class);
            item.setCount(item.getCount()+num);

            String s = JSON.toJSONString(item);
            cartOps.put(skuId.toString(),s);

            return item;
        }
    }

    @Override
    public CartItem getCartItem(Long skuId) {

        BoundHashOperations<String, Object, Object> cart = getCartOps();

        String item = (String) cart.get(skuId.toString());

        CartItem cartItem = JSON.parseObject(item, CartItem.class);

        return cartItem;
    }

    @Override
    public Cart getCart() {

        userInfoTo userInfoTo = CartInterceptor.threadLocal.get();

//        System.out.println(userInfoTo);

        Cart cart = new Cart();

//        BoundHashOperations<String, Object, Object> operations = getCartOps();

        if(userInfoTo.getUserId() != null){
            //登录
            String cartId = CART_PREFIX+userInfoTo.getUserId();

            //将离线购物车的数据保存到在线购物车
            String cartKey = CART_PREFIX+userInfoTo.getUserKey();

            List<CartItem> tempCartItems = getCartItem(cartKey);

            if(tempCartItems != null){

                for (CartItem cartitem : tempCartItems) {
                    addToCart(cartitem.getSkuId(), cartitem.getCount());
                    redisTemplate.boundHashOps(cartKey).delete(cartitem.getSkuId().toString());
                }
//                redisTemplate.boundHashOps(cartKey).delete(cartKey);

            }

            //3、获取登录后的购物车的数据【包含合并过来的临时购物车的数据，和登录后的购物车的数据】
            List<CartItem> cartItems = getCartItem(cartId);

            cart.setItems(cartItems);

        }else{
            //没登录
            String cartKey = CART_PREFIX+userInfoTo.getUserKey();

            List<CartItem> cartItems = getCartItem(cartKey);

            cart.setItems(cartItems);
        }

        return cart;
    }

    @Override
    public void checkItem(Long skuId, int check) {

        CartItem cartItem = getCartItem(skuId);
        cartItem.setCheck(check==1?true:false);

        BoundHashOperations<String, Object, Object> cart = getCartOps();

        String s = JSON.toJSONString(cartItem);
        cart.put(skuId.toString(),s);
    }

    @Override
    public void deleteItem(String skuId) {

        BoundHashOperations<String, Object, Object> cart = getCartOps();
        cart.delete(skuId);

    }


    private List<CartItem> getCartItem(String cartKey) {

        BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);

        List<Object> list = operations.values();

        List<CartItem> collect = new ArrayList<>();

        if(list != null && list.size() > 0){

            collect = list.stream().map((item) -> {

                CartItem cartItem = JSON.parseObject(item.toString(), CartItem.class);

                return cartItem;
            }).collect(Collectors.toList());

        }
        return collect;
    }

    /**
     * 获取到我们要添加的购物车
     * @return
     */
    private BoundHashOperations<String, Object, Object> getCartOps() {
        userInfoTo userInfoTo = CartInterceptor.threadLocal.get();

        String cartKey = "";

        if(userInfoTo.getUserId() != null){

            cartKey = CART_PREFIX+userInfoTo.getUserId();
        }else{
            cartKey = CART_PREFIX+userInfoTo.getUserKey();
        }

        BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);


        return operations;
    }

}
